package org.leon.dubbo.filter;

import java.util.HashMap;
import java.util.Map;
import java.util.TimerTask;

public class MonitorJob extends TimerTask {

    // 参考文章: https://blog.csdn.net/qq_35246620/article/details/101284451

    // 记录每个方法的每次耗时的次数
    Map<String, Long[]> methodMonitor = new HashMap<>();
    // 记录每个方法的调用总数
    Map<String, Long> methodCallCount = new HashMap<>();

    public MonitorJob() {
        super();
    }

    @Override
    public void run() {
        synchronized (this) {
            for (String methodName : methodCallCount.keySet()) {
                statMethodPerformance(methodName);
            }
            System.out.println("---------------------------");
        }
    }

    private void statMethodPerformance(String methodName) {
        Long[] mc = methodMonitor.get(methodName);
        Long total = methodCallCount.get(methodName);

        /*System.out.print(methodName + " 次数 :");
        for (int i = 0; i < mc.length; i++) {
            System.out.print(mc[i] + " ");
        }
        System.out.println();*/

        // 计算TP99
        int c = (int) Math.ceil(total * 0.99);
        int s = 0;
        int i = 0;
        for (; i < mc.length; i++) {
            s += mc[i];
            if (s >= c) {
                break;
            }
        }
        String tp99 = "TP99 性能指标: " + i + "ms";

        // 计算TP90
        c = (int) Math.ceil(total * 0.90);
        s = 0;
        i = 0;
        for (; i < mc.length; i++) {
            s += mc[i];
            if (s >= c) {
                break;
            }
        }
        System.out.println(methodName + " TP90 性能指标: " + i + "ms; " + tp99);
    }

    public void reportResponseTime(String methodName, long timeSpend) {
        synchronized (this) {
            if (methodMonitor.containsKey(methodName)){
                Long[] cc = methodMonitor.get(methodName);
                if (timeSpend >= cc.length) {
                    cc[cc.length-1] ++;
                } else {
                    cc[(int)timeSpend] ++;
                }
                methodCallCount.put(methodName, methodCallCount.get(methodName) + 1);
            } else {
                // 统计数组: 统计每个耗时出现的次数 (由于本测试程序的响应基本在 100ms 以内, 因此数组长度设置为 200 足够了)
                // 第一次记录,初始化每个响应时间的次数为 0
                Long[] c = new Long[200];
                for (int i = 0; i < c.length; i++) {
                    c[i] = 0L;
                }
                // 本次响应时间次数累加
                if (timeSpend >= c.length) {
                    c[c.length-1] ++;
                } else {
                    c[(int)timeSpend] ++;
                }

                methodMonitor.put(methodName, c);
                methodCallCount.put(methodName, 1L);
            }

        }
    }
}
